package com.damai.action.request;

import java.io.File;
import java.io.IOException;
import java.lang.reflect.Method;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import com.citywithincity.api.ApiConfig;
import com.citywithincity.db.interfaces.IValueConvert;
import com.citywithincity.reflect.CtClassUtil;
import com.citywithincity.utils.FormUploadUtil;
import com.citywithincity.utils.FormUploadUtil.UploadFile;
import com.citywithincity.utils.FormUploadUtil.UploadGroup;
import com.citywithincity.utils.IoUtil;
import com.citywithincity.utils.RequestUtil;
import com.citywithincity.web.request.IRequestData;
import com.citywithincity.web.request.RequestDataFactory;
import com.damai.action.IParamParser;
import com.damai.action.IParamParserFactory;
import com.damai.action.json.IParamGetter;
import com.damai.action.json.JsonParamParserFactory;
import com.damai.action.json.SimpleParamGetter;
import com.damai.utils.value.ValueConvertFactory;

import javassist.ClassPool;

public class RequestParamParserFactory implements IParamParserFactory {
	
	public static final IParamParserFactory DEFAULT = new RequestParamParserFactory();
	
	private RequestParamParserFactory(){
		
	}
	
	class RequestParamParser implements IParamParser{
		private String[] names;
		private IRequestData[] datas;
		public RequestParamParser(String[] names,IRequestData[] datas) {
			this.names = names;
			this.datas = datas;
		}

		@Override
		public Object[] parseParam(HttpServletRequest request) throws IOException {

			
			final String[] names = this.names;
			final IRequestData[] datas= this.datas;
			
			Object[] result = new Object[names.length];
			int index = 0;
			for (IRequestData data : datas) {
				String name = names[index];
				result[index++]=data.getValue(request, name);
			}
			
			
			if(ApiConfig.debug()){
				ApiConfig.info(String.format("%s %s", request.getRequestURI(),  RequestUtil.requestToMap(request) ));
			}
			
			
			return result;
		}
		
	}
	
	
	
	
	class RequestParamParserWithFile implements IParamParser{
		private IParamGetter[] datas;
		public RequestParamParserWithFile(IParamGetter[] datas) {
			this.datas = datas;
		}

		@Override
		public Object[] parseParam(HttpServletRequest request) throws IOException {
			
			UploadGroup uploadGroup =  FormUploadUtil.doUpload(request);
			Map<String, Object> uploadData = uploadGroup.getMap();
			
			final IParamGetter[] datas= this.datas;
			
			Object[] result = new Object[datas.length];
			int index = 0;
			for (IParamGetter data : datas) {
				result[index++]=data.get(uploadData);
			}
			
			if(ApiConfig.debug()){
				ApiConfig.info(String.format("%s %s", request.getRequestURI(), uploadData ));
			}
			
			
			return result;
		}
		
	}
	
	private static class SimpleParamGetterConvert implements IParamGetter{
		private IValueConvert convert;
		private String name;
		private SimpleParamGetterConvert(IValueConvert convert,String name){
			this.convert = convert;
			this.name = name;
		}

		@Override
		public Object get(Map<String, Object> json) {
			Object value = json.get(name);
			return convert.convert(value);
		}
	}
	
	private static class SimpleParamGetterByte implements IParamGetter{
		private String name;
		private SimpleParamGetterByte(String name){
			this.name = name;
		}

		@Override
		public Object get(Map<String, Object> json) {
			UploadFile value = (UploadFile) json.get(name);
			try {
				return IoUtil.readFromFile(value.getFile());
			} catch (IOException e) {
				return new byte[]{};
			}
		}
	}
	
	private static class SimpleParamGetterFile implements IParamGetter{
		private String name;
		private SimpleParamGetterFile(String name){
			this.name = name;
		}

		@Override
		public Object get(Map<String, Object> json) {
			UploadFile value = (UploadFile) json.get(name);
			return value.getFile();
		}
	}
	
	
	private IParamGetter createParamGetter(Class<?> type,String name) throws Exception{
		if(type == byte[].class){
			
			return new SimpleParamGetterByte(name);
		
			
		}else if(type == File.class)
		{
			return new SimpleParamGetterFile(name);
		}else if(type == UploadFile.class){
			return new SimpleParamGetter(name);
		}
		
		if(type == String.class){
			return new SimpleParamGetter(name);
		}
		return new SimpleParamGetterConvert(ValueConvertFactory.create(String.class,type ),name);
	}
	
	
	@Override
	public IParamParser createParser(ClassPool classPool,Class<?> controllerClass, Method method) {
		try {
			String[] names = CtClassUtil.getParams(classPool,controllerClass, method);
			Class<?>[] types = method.getParameterTypes();
			int count = types.length;
			
			if(JsonParamParserFactory.containsFile(method)){
				//使用灵位一种
				IParamGetter[] datas = new IParamGetter[count];
				for (int i = 0; i < count; ++i) {
					IParamGetter data = createParamGetter(types[i], names[i]);
					datas[i] = data;
				}
				return new RequestParamParserWithFile(datas);
			}else{
				IRequestData[] datas = new IRequestData[count];
				for (int i = 0; i < count; ++i) {
					IRequestData data  = RequestDataFactory.create(types[i]);
					datas[i] = data;
				}
				
				return new RequestParamParser(names,datas);
			}
			
			
			
		} catch (Exception e) {
			ApiConfig.error("Create param getter error:" + controllerClass.getName() + " method:" + method.getName(),e);
			throw new RuntimeException(e);
		}
	}

	

}
